/*
 * $Id: grep.h,v 1.19 2005-12-11 13:36:43 bacon Exp $
 */

#ifndef _XP_UTL_GREP_H_
#define _XP_UTL_GREP_H_

#include <xp/types.h>
#include <xp/macros.h>
#include <xp/bas/str.h>

enum 
{
	XP_GREP_IO_OPEN,
	XP_GREP_IO_CLOSE,
	XP_GREP_IO_DATA
};

enum
{
	XP_GREP_ENOERR = 0,
	XP_GREP_ENOMEM, /* out of memory */
	XP_GREP_ENOINF, /* no input function attached */
	XP_GREP_EINPUT, /* input function returned an error */
	XP_GREP_EINPOP, /* input function failed to open */
	XP_GREP_EINPCL, /* input function failed to close */
	XP_GREP_ENOMTR, /* no matcher attached */
	XP_GREP_EMATCH  /* matcher returned an error */
};

#define XP_GREP_ERRNUM(grep) ((grep)->errnum)

/*
 * TYPE: xp_grep_t
 *   Defines a grep object
 *
 * DESCRIPTION:
 *   <xp_grep_t> is a structure to represent a grep object. The grep object
 *   emulates the functionality of the grep command available in many operating
 *   systems.
 */
typedef struct xp_grep_t xp_grep_t;

/* 
 * TYPE: xp_grep_io_t
 *   Defines an IO handler type
 *
 * DESCRIPTION:
 *   An IO handler is a user-defined function to be called when IO is required.
 *   <xp_grep_t> requires two IO handlers, one for input and the other output.
 *   It has the following prototype.
 *
 *   * xp_ssize_t grep_io_func (int cmd, void* arg, xp_char_t* data, xp_size_t count);
 *
 *   It should support three different operations depending on the value of *cmd*.
 *   
 *   * XP_GREP_IO_OPEN - opens a stream
 *   * XP_GREP_IO_CLOSE - closes a stream
 *   * XP_GREP_IO_DATA - read or write data 
 *
 *   The argument set with <xp_grep_attach_input> and <xp_grep_attach_output>
 *   is passed to the handler as the second argument(*arg*) for input and 
 *   output respectively.
 * 
 *   XP_GREP_IO_OPEN and XP_GREP_IO_CLOSE do not use *data* and *count*. The
 *   handler should return 0 on success and -1 on failure for open and close
 *   operations.
 * 
 *   XP_GREP_IO_DATA is used to read input for the input handler and write 
 *   output for the output handler. The input handler should return 0 when 
 *   it reaches the end of input, -1 on error, and the number of characters
 *   read. The output handler should return -1 on error and the number of
 *   characters written.
 */
typedef xp_ssize_t (*xp_grep_io_t) (
	int cmd, void* arg, xp_char_t* data, xp_size_t count);

/* 
 * TYPE: xp_grep_matcher_t
 *   Defines a matcher function
 * 
 * DESCRIPTION:
 *   A matcher should match input data of given size with its match logic 
 *   and return one of the following values. 
 *     * XP_GREP_CONTINUE
 *     * XP_GREP_RETURN_MATCH
 *     * XP_GREP_RETURN_NOMATCH
 *     * XP_GREP_RETURN_ERROR
 *   The input size is measured in the number of characters. The matcher 
 *   argument set with <xp_grep_attach_matcher> is passed as the first argument.
 *
 *     * int matcher_func (void* arg, const xp_char_t* input_data, xp_size_t input_size);
 */

enum
{
	XP_GREP_CONTINUE       = 0,
	XP_GREP_RETURN_MATCH   = 1,
	XP_GREP_RETURN_NOMATCH = 2,
	XP_GREP_RETURN_ERROR   = 3
};

typedef int (*xp_grep_matcher_t) (
	void* arg, const xp_char_t* input_data, xp_size_t input_size);

/*
 * TYPE: xp_grep_match_t
 *   Defines a structure to hold match information
 *
 * DESCRIPTION:
 *   <xp_grep_match> returns a match result in <xp_grep_match_t>. It includes
 *   the line number of the input, the entire line, and the matched portion.
 */
typedef struct xp_grep_match_t xp_grep_match_t;

struct xp_grep_t
{
	/* matcher */
	xp_grep_matcher_t matcher;
	void* matcher_arg;

	/* io functions */
	xp_grep_io_t input_func;
	xp_grep_io_t output_func;
	void* input_arg;
	void* output_arg;

	/* for housekeeping */
	xp_str_t line;
	xp_char_t buf[256];
	xp_size_t buf_cur;
	xp_size_t buf_len;
	int errnum;
	xp_size_t __linenum;
	xp_bool_t __atend;
	xp_bool_t __dynamic;
};

struct xp_grep_match_t
{
	xp_bool_t matched;
	const xp_char_t* line;
	xp_size_t line_len;
	xp_size_t line_num;
};

#ifdef __cplusplus
extern "C" {
#endif

/*
 * FUNCTION: xp_grep_open 
 *   Instantiates a grep object.
 *
 * PARAMETERS:
 *   grep - XP_NULL or a pointer to a uninitialized variable of xp_grep_t
 *
 * RETURNS:
 *   Pointer to the grep object instantiated on success, XP_NULL on failure
 * 
 * DESCRIPTION:
 *   <xp_grep_open> allocates the memory required for the object instantiation
 *   and initializes it if *grep* is XP_NULL. It returns XP_NULL when the memory 
 *   allocation fails. It returns the pointer to the object created on success.
 *
 *   If *grep* is not XP_NULL, it skips to the initialization directly and
 *   returns the pointer value *grep* is holding.
 * 
 * SEE ALSO:
 *   <xp_grep_close>
 */
xp_grep_t* xp_grep_open (xp_grep_t* grep);

/*
 * FUNCTION: xp_grep_close
 *   Destroys a grep object
 * 
 * PARAMETERS:
 *   grep - pointer to a grep object
 *
 * DESCRIPTION:
 *   <xp_grep_close> frees resources it might hold.
 *
 * DESCRIPTION:
 */
int xp_grep_close (xp_grep_t* grep);

/*
 * FUNCTION: xp_grep_errnum
 *   Returns an error code
 *
 * PARAMETERS:
 *   grep - a grep object
 *
 * RETURNS:
 *   Error code set by the last grep function called
 */
int xp_grep_errnum (xp_grep_t* grep);

/*
 * FUNCTION: xp_grep_errstr
 *   Translates an error code to a string
 *
 * PARAMETERS:
 *   grep - a grep object
 *
 * RETURNS:
 *   A pointer to a constant string describing the last error occurred
 */
const xp_char_t* xp_grep_errstr (xp_grep_t* grep);

/*
 * FUNCTION: xp_grep_attach_input
 *   Attaches an input handler function
 *
 * PARAMETERS:
 *   grep - a grep object
 *   input - input handler function
 *   arg - user data to be passed to the input handler
 * 
 * RETURNS:
 *   0 on success, -1 on failure
 */
int xp_grep_attach_input (xp_grep_t* grep, xp_grep_io_t input, void* arg);

/*
 * FUNCTION: xp_grep_detach_input
 *   Detaches an input handler function
 *
 * PARAMETERS:
 *   grep - a grep object
 * 
 * RETURNS:
 *   0 on success, -1 on failure
 */
int xp_grep_detach_input (xp_grep_t* grep);

/*
 * FUNCTION: xp_grep_attach_output
 *   Attaches an output handler function
 *
 * PARAMETERS:
 *   grep - a grep object
 *   output - output handler function
 *   arg - user data to be passed to the output handler
 * 
 * RETURNS:
 *   0 on success, -1 on failure
 */
int xp_grep_attach_output (xp_grep_t* grep, xp_grep_io_t output, void* arg);

/*
 * FUNCTION: xp_grep_detach_output
 *   Detaches an output handler function
 * 
 * PARAMETERS:
 *   grep - a grep object
 *
 * RETURNS:
 *   0 on success, -1 on failure
 */
int xp_grep_detach_output (xp_grep_t* grep);

/*
 * FUNCTION: xp_grep_attach_matcher
 *   Attaches a matcher
 *
 * PARAMETERS:
 *   grep - a grep object
 *   matcher - a matcher function
 *   arg - user data to be passed to the matcher
 * 
 * RETURNS:
 *   0 on success, -1 on failure
 */
int xp_grep_attach_matcher (
	xp_grep_t* grep, xp_grep_matcher_t matcher, void* arg);

/*
 * FUNCTION: xp_grep_detach_matcher
 *   Detaches a matcher
 * 
 * PARAMETERS:
 *   grep - a grep object
 *
 * RETURNS:
 *   0 on success, -1 on failure
 * 
 * DESCRIPTION:
 *   <xp_grep_detach_matcher> detaches the user-defined matcher function.
 *   <xp_grep_match> falls back to the builtin match mechanism.
 * 
 * SEE ALSO:
 *   <xp_grep_attach_matcher> <xp_grep_match>
 */
int xp_grep_detach_matcher (xp_grep_t* grep);

/*
 * FUNCTION: xp_grep_match 
 *   Performs the match
 *
 * PARAMETERS:
 *   grep - a grep object
 *   flags - 0 or XP_GREP_INVERT
 *   match - match information
 *
 * RETURNS:
 *   -1 on error, 0 on end of input, 1 when a match is found
 *
 * DESCRIPTION:
 *   <xp_grep_match> searches the input for a match and returns the match
 *   in *match*. XP_GREP_INVERT in *flags* invert the meaning of the match.
 *   <xp_grep_match> can usually be called repeatedly until it returns 0 or -1.
 */
int xp_grep_match (xp_grep_t* grep, xp_grep_match_t* match);

/*
 * FUNCTION: xp_grep_match_substr
 *   A sample matcher
 *
 * DESCRIPTION:
 *   <xp_grep_match_substr> is a dumb matcher provided for reference.
 *   This matcher can just retrieve the entire line matching the rule.
 */
int xp_grep_match_substr (
        void* arg, const xp_char_t* input_data, xp_size_t input_size);

#ifdef __cplusplus
}
#endif

#endif
